﻿module DataTypes

open Microsoft.Xna.Framework
open Microsoft.FSharp.Core.LanguagePrimitives

open Measure



//type Vector2<[<Measure>] 'a> =
//    struct
//        val x : float32<'a>
//        val y : float32<'a>
// 
//        new(xIn: float32<'a>, yIn: float32<'a>) = { x = xIn; y = yIn }
//        static member Zero : Vector2<_> = Vector2(0.0f<_>, 0.0f<_>)
//        static member One : Vector2<_> = Vector2(1.0f<_>, 1.0f<_>)
//        static member UnitX : Vector2<_> = Vector2(1.0f<_>, 0.0f<_>)
//        static member UnitY : Vector2<_> = Vector2(0.0f<_>, 1.0f<_>)
//
//        static member ( + ) (v1:Vector2<'a>,v2:Vector2<'a>):Vector2<'a> = Vector2(v1.x + v2.x, v1.y + v2.y)
//        static member ( + ) (v:Vector2<'a>,k:float32<'a>):Vector2<'a> =  Vector2(v.x + k, v.y + k)
//        static member ( + ) (k:float32<'a>,v:Vector2<'a>):Vector2<'a> = v + k
//      
//        static member ( ~- ) (v:Vector2<'a>):Vector2<'a> = Vector2(-v.x, -v.y)
//      
//        static member ( - ) (v1:Vector2<'a>,v2:Vector2<'a>):Vector2<'a> = v1 + (-v2)
//        static member ( - ) (v:Vector2<'a>,k:float32<'a>):Vector2<'a> = v + (-k)
//        static member ( - ) (k:float32<'a>,v:Vector2<'a>):Vector2<'a> = k + (-v)
// 
//        static member ( * ) (v1:Vector2<'a>,v2:Vector2<'b>):Vector2<'a * 'b> = Vector2(v1.x * v2.x, v1.y * v2.y)
//        static member ( * ) (v:Vector2<'a>,f:float32<'b>):Vector2<'a * 'b> = Vector2(v.x * f, v.y * f)
//        static member ( * ) (f:float32<'b>,v:Vector2<'a>):Vector2<'b * 'a> = Vector2(f * v.x, f * v.y)
//
//        static member ( / ) (v:Vector2<'a>,f:float32<'b>):Vector2<'a / 'b> = v * (1.0f / f)
//
//        member this.Length : float32<'a> = sqrt((this.x * this.x + this.y * this.y))
//
//        static member Distance(v1:Vector2<'a>,v2:Vector2<'a>) = (v1-v2).Length
//        static member Normalize(v:Vector2<'a>):Vector2<1> = v / v.Length
//
//        member this.Normalized = this / this.Length
//
//        static member Dot(v1:Vector2<'a>,v2:Vector2<'a>) = v1.x * v2.x + v1.y * v2.y
//        static member Cross(v1:Vector2<'a>,v2:Vector2<'a>) = v1.x * v2.y - v1.y * v2.x
//    end
//
//
//
//type Vector3<[<Measure>] 'a> =
//    struct
//        val x : float32<'a>
//        val y : float32<'a>
//        val z : float32<'a>
// 
//        new(xIn: float32<'a>, yIn: float32<'a>, zIn: float32<'a>) = { x = xIn; y = yIn; z = zIn }
//        static member Zero : Vector3<_> = Vector3(0.0f<_>, 0.0f<_>, 0.0f<_>)
//        static member One : Vector3<_> = Vector3(1.0f<_>, 1.0f<_>, 1.0f<_>)
//        static member UnitX : Vector3<_> = Vector3(1.0f<_>, 0.0f<_>, 0.0f<_>)
//        static member UnitY : Vector3<_> = Vector3(0.0f<_>, 1.0f<_>, 0.0f<_>)
//        static member UnitZ : Vector3<_> = Vector3(0.0f<_>, 0.0f<_>, 1.0f<_>)
//
//        static member ( + ) (v1:Vector3<'a>,v2:Vector3<'a>):Vector3<'a> = Vector3(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z)
//        static member ( + ) (v:Vector3<'a>,k:float32<'a>):Vector3<'a> =  Vector3(v.x + k, v.y + k, v.z + k)
//        static member ( + ) (k:float32<'a>,v:Vector3<'a>):Vector3<'a> = v + k
//      
//        static member ( ~- ) (v:Vector3<'a>):Vector3<'a> = Vector3(-v.x, -v.y, -v.z)
//      
//        static member ( - ) (v1:Vector3<'a>,v2:Vector3<'a>):Vector3<'a> = v1 + (-v2)
//        static member ( - ) (v:Vector3<'a>,k:float32<'a>):Vector3<'a> = v + (-k)
//        static member ( - ) (k:float32<'a>,v:Vector3<'a>):Vector3<'a> = k + (-v)
// 
//        static member ( * ) (v1:Vector3<'a>,v2:Vector3<'b>):Vector3<'a * 'b> = Vector3(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z)
//        static member ( * ) (v:Vector3<'a>,f:float32<'b>):Vector3<'a * 'b> = Vector3(v.x * f, v.y * f, v.z * f)
//        static member ( * ) (f:float32<'b>,v:Vector3<'a>):Vector3<'b * 'a> = Vector3(f * v.x, f * v.y, f * v.z)
//
//        static member ( / ) (v:Vector3<'a>,f:float32<'b>):Vector3<'a / 'b> = v * (1.0f / f)
//
//        member this.Length : float32<'a> = sqrt((this.x * this.x + this.y * this.y + this.z * this.z))
//
//        static member Distance(v1:Vector3<'a>,v2:Vector3<'a>) = (v1-v2).Length
//        static member Normalize(v:Vector3<'a>):Vector3<1> = v / v.Length
//
//        member this.Normalized = this / this.Length
//
//        static member Dot(v1:Vector3<'a>,v2:Vector3<'a>) = v1.x * v2.x + v1.y * v2.y + v1.z * v2.z
//        static member Cross(v1:Vector3<'a>,v2:Vector3<'a>):Vector3<'a*'b> =
//            Vector3(v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z, v1.x * v2.y - v1.y * v2.x)
//    end



type Vector2<[< Measure >] 'u> =
    struct
        val mutable internal vector : Microsoft.Xna.Framework.Vector2

        member this.X 
            with get() = (this.vector.X |> Float32WithMeasure) : float32<'u>
            and set (v:float32<'u>) = this.vector.X <- v |> float32
        member this.Y 
            with get() = (this.vector.Y |> Float32WithMeasure) : float32<'u>
            and set (v:float32<'u>) = this.vector.Y <- v |> float32

        override this.ToString() = this.vector.ToString()

        new(x: float32<'u>, y: float32<'u>) = { vector = Microsoft.Xna.Framework.Vector2(x |> float32, y |> float32) }
        new(v: float32<'u>) = { vector = Microsoft.Xna.Framework.Vector2(v |> float32, v |> float32) }
        private new(v: Microsoft.Xna.Framework.Vector2) = { vector = v }

        static member Zero with get() = Vector2<'u>(Microsoft.Xna.Framework.Vector2.Zero)
        static member One with get() = Vector2<'u>(Microsoft.Xna.Framework.Vector2.One)
        static member UnitX with get() = Vector2<'u>(Microsoft.Xna.Framework.Vector2.UnitX)
        static member UnitY with get() = Vector2<'u>(Microsoft.Xna.Framework.Vector2.UnitY)

        static member (+) (v1:Vector2<'u>, v2:Vector2<'u>) = Vector2<'u>(v1.vector + v2.vector)
        static member (+) (v1:Vector2<'u>, f:float32<'u>) = Vector2<'u>(v1.X + f, v1.Y + f)
        static member (-) (v1:Vector2<'u>, v2:Vector2<'u>) = Vector2<'u>(v1.vector - v2.vector)
        static member (-) (v1:Vector2<'u>, f:float32<'u2>) = Vector2<'u>(v1.X - f, v1.Y - f)
        static member (*) (v1:Vector2<'u>, v2:Vector2<'u2>) = Vector2<'u * 'u2>(v1.X * v2.X, v1.Y * v2.Y)
        static member (*) (v1:Vector2<'u>, f:float32<'u2>) = Vector2<'u * 'u2>(v1.vector * (float32 f))
        static member (*) (f:float32<'u2>, v1:Vector2<'u>) = Vector2<'u * 'u2>(v1.vector * (float32 f))
        static member (/) (v1:Vector2<'u>, f:float32<'u2>) = Vector2<'u/'u2>(v1.vector / (float32 f))
        static member (/) (v1:Vector2<'u>, v2:Vector2<'u2>) = Vector2<'u/'u2>(v1.X / v2.X, v1.Y / v2.Y)
        static member (~-) (v:Vector2<'u>) = Vector2<'u>(-v.vector)

        static member inline private lift2 (f:Microsoft.Xna.Framework.Vector2*Microsoft.Xna.Framework.Vector2->'a)
            (v1:Vector2<'u1>, v2:Vector2<'u2>) = f(v1.vector,v2.vector)

        static member Transform (v:Vector2<'u>,m:Microsoft.Xna.Framework.Matrix) =
            Vector2<'u>(Microsoft.Xna.Framework.Vector2.Transform (v.vector, m))

        static member Dot (v1:Vector2<'u1>,v2:Vector2<'u2>) =
            Vector2<'u>.lift2 (Microsoft.Xna.Framework.Vector2.Dot) (v1,v2) |> Float32WithMeasure : float32<'u1 * 'u2>

        static member Distance (v1:Vector2<'u>, v2:Vector2<'u>) =
            Vector2<'u>.lift2 (Microsoft.Xna.Framework.Vector2.Distance) (v1,v2) |> Float32WithMeasure : float32<'u>

        static member DistanceSquared (v1:Vector2<'u>, v2:Vector2<'u>) =
            Vector2<'u>.lift2 (Microsoft.Xna.Framework.Vector2.DistanceSquared) (v1,v2) |> Float32WithMeasure : float32<'u * 'u>

        static member Min (v1:Vector2<'u>, v2:Vector2<'u>) = Vector2<'u>(min v1.X v2.X, min v1.Y v2.Y)
        static member Max (v1:Vector2<'u>, v2:Vector2<'u>) = Vector2<'u>(max v1.X v2.X, max v1.Y v2.Y)

        static member Clamp (lower:Vector2<'u>, upper:Vector2<'u>, v:Vector2<'u>) = 
            let clamp l u v = v |> max l |> min u
            Vector2<'u>(clamp lower.X upper.X v.X, clamp lower.Y upper.Y v.Y)

        member this.Length() = this.vector.Length() |> Float32WithMeasure : float32<'u>
        member this.LengthSquared() = this.vector.LengthSquared() |> Float32WithMeasure : float32<'u * 'u>

        static member Normalize(v:Vector2<'u>) = Vector2<1>(Vector2.Normalize v.vector)

        member this.Normalized() = Vector2<1>(Microsoft.Xna.Framework.Vector2.Normalize(this.vector))

        member this.GetNative() = this.vector
    end



type Vector3<[< Measure >] 'u> =
    struct
        val mutable internal vector : Microsoft.Xna.Framework.Vector3

        member this.X 
            with get() = (this.vector.X |> Float32WithMeasure) : float32<'u>
            and set (v:float32<'u>) = this.vector.X <- v |> float32
        member this.Y 
            with get() = (this.vector.Y |> Float32WithMeasure) : float32<'u>
            and set (v:float32<'u>) = this.vector.Y <- v |> float32
        member this.Z 
            with get() = (this.vector.Z |> Float32WithMeasure) : float32<'u>
            and set (v:float32<'u>) = this.vector.Z <- v |> float32

        override this.ToString() = this.vector.ToString()

        new(x: float32<'u>, y: float32<'u>, z: float32<'u>) =
            { vector = Microsoft.Xna.Framework.Vector3(x |> float32, y |> float32, z |> float32) }
        new(v: float32<'u>) = { vector = Microsoft.Xna.Framework.Vector3(v |> float32, v |> float32, v |> float32) }
        private new(v: Microsoft.Xna.Framework.Vector3) = { vector = v }

        static member Zero with get() = Vector3<'u>(Microsoft.Xna.Framework.Vector3.Zero)
        static member One with get() = Vector3<'u>(Microsoft.Xna.Framework.Vector3.One)
        static member UnitX with get() = Vector3<'u>(Microsoft.Xna.Framework.Vector3.UnitX)
        static member UnitY with get() = Vector3<'u>(Microsoft.Xna.Framework.Vector3.UnitY)
        static member UnitZ with get() = Vector3<'u>(Microsoft.Xna.Framework.Vector3.UnitZ)
        static member UnitXInverse with get() = Vector3<'u>(Microsoft.Xna.Framework.Vector3(-1.0f, 0.0f, 0.0f))
        static member UnitYInverse with get() = Vector3<'u>(Microsoft.Xna.Framework.Vector3(0.0f, -1.0f, 0.0f))
        static member UnitZInverse with get() = Vector3<'u>(Microsoft.Xna.Framework.Vector3(0.0f, 0.0f, -1.0f))

        static member (+) (v1:Vector3<'u>, v2:Vector3<'u>) = Vector3<'u>(v1.vector + v2.vector)
        static member (+) (v1:Vector3<'u>, f:float32<'u>) = Vector3<'u>(v1.X + f, v1.Y + f, v1.Z + f)
        static member (-) (v1:Vector3<'u>, v2:Vector3<'u>) = Vector3<'u>(v1.vector - v2.vector)
        static member (-) (v1:Vector3<'u>, f:float32<'u2>) = Vector3<'u>(v1.X - f, v1.Y - f, v1.Z - f)
        static member (*) (v1:Vector3<'u>, v2:Vector3<'u2>) = Vector3<'u * 'u2>(v1.X * v2.X, v1.Y * v2.Y, v1.Z * v2.Z)
        static member (*) (v1:Vector3<'u>, f:float32<'u2>) = Vector3<'u * 'u2>(v1.vector * (float32 f))
        static member (*) (f:float32<'u2>, v1:Vector3<'u>) = Vector3<'u * 'u2>(v1.vector * (float32 f))
        static member (/) (v1:Vector3<'u>, f:float32<'u2>) = Vector3<'u/'u2>(v1.vector / (float32 f))
        static member (/) (v1:Vector3<'u>, v2:Vector3<'u2>) = Vector3<'u/'u2>(v1.X / v2.X, v1.Y / v2.Y, v1.Z / v2.Z)
        static member (~-) (v:Vector3<'u>) = Vector3<'u>(-v.vector)

        static member inline private lift2 (f:Microsoft.Xna.Framework.Vector3*Microsoft.Xna.Framework.Vector3->'a)
            (v1:Vector3<'u1>, v2:Vector3<'u2>) = f(v1.vector,v2.vector)

        static member Cross (v1:Vector3<_>,v2:Vector3<_>) =
            Vector3<_>(Vector3<_>.lift2 (Microsoft.Xna.Framework.Vector3.Cross) (v1, v2))

        static member Dot (v1:Vector3<'u1>,v2:Vector3<'u2>) =
            Vector3<'u>.lift2 (Microsoft.Xna.Framework.Vector3.Dot) (v1, v2) |> Float32WithMeasure : float32<'u1 * 'u2>

        static member Distance (v1:Vector3<'u>, v2:Vector3<'u>) =
            Vector3<'u>.lift2 (Microsoft.Xna.Framework.Vector3.Distance) (v1,v2) |> Float32WithMeasure : float32<'u>

        static member DistanceSquared (v1:Vector3<'u>, v2:Vector3<'u>) =
            Vector3<'u>.lift2 (Microsoft.Xna.Framework.Vector3.DistanceSquared) (v1,v2) |> Float32WithMeasure : float32<'u * 'u>

        static member Min (v1:Vector3<'u>, v2:Vector3<'u>) = Vector3<'u>(min v1.X v2.X, min v1.Y v2.Y, min v1.Z v2.Z)
        static member Max (v1:Vector3<'u>, v2:Vector3<'u>) = Vector3<'u>(max v1.X v2.X, max v1.Y v2.Y, max v1.Z v2.Z)

        static member Clamp (lower:Vector3<'u>, upper:Vector3<'u>, v:Vector3<'u>) = 
            let clamp l u v = v |> max l |> min u
            Vector3<'u>(clamp lower.X upper.X v.X, clamp lower.Y upper.Y v.Y, clamp lower.Z upper.Z v.Z)

        static member Lerp (a:float32, v1:Vector3<'u>, v2:Vector3<'u>) = 
            assert(a >= 0.0f && a <= 1.0f)
            a*v1 + (1.0f-a)*v2

        member this.Length() = this.vector.Length() |> Float32WithMeasure : float32<'u>

        member this.LengthSquared() = this.vector.LengthSquared() |> Float32WithMeasure : float32<'u * 'u>

        static member Normalize(v:Vector3<'u>) = Vector3<1>(Vector3.Normalize v.vector)

        member this.Normalized() = Vector3<1>(Microsoft.Xna.Framework.Vector3.Normalize(this.vector))

        member this.GetNative() = this.vector
    end



type Matrix<[< Measure >] 'u> =
    struct
        val mutable internal matrix : Microsoft.Xna.Framework.Matrix

        member this.M11
          with get() = (this.matrix.M11 |> Float32WithMeasure) : float32<1>
          and set (m:float32<1>) = this.matrix.M11 <- m |> float32
        member this.M12
          with get() = (this.matrix.M12 |> Float32WithMeasure) : float32<1>
          and set (m:float32<1>) = this.matrix.M12 <- m |> float32
        member this.M13
          with get() = (this.matrix.M13 |> Float32WithMeasure) : float32<1>
          and set (m:float32<1>) = this.matrix.M13 <- m |> float32
        member this.M14
          with get() = (this.matrix.M14 |> Float32WithMeasure) : float32<1>
          and set (m:float32<1>) = this.matrix.M14 <- m |> float32
        member this.M21
          with get() = (this.matrix.M21 |> Float32WithMeasure) : float32<1>
          and set (m:float32<1>) = this.matrix.M21 <- m |> float32
        member this.M22
          with get() = (this.matrix.M22 |> Float32WithMeasure) : float32<1>
          and set (m:float32<1>) = this.matrix.M22 <- m |> float32
        member this.M23
          with get() = (this.matrix.M23 |> Float32WithMeasure) : float32<1>
          and set (m:float32<1>) = this.matrix.M23 <- m |> float32
        member this.M24
          with get() = (this.matrix.M24 |> Float32WithMeasure) : float32<1>
          and set (m:float32<1>) = this.matrix.M24 <- m |> float32
        member this.M31
          with get() = (this.matrix.M31 |> Float32WithMeasure) : float32<1>
          and set (m:float32<1>) = this.matrix.M31 <- m |> float32
        member this.M32
          with get() = (this.matrix.M32 |> Float32WithMeasure) : float32<1>
          and set (m:float32<1>) = this.matrix.M32 <- m |> float32
        member this.M33
          with get() = (this.matrix.M33 |> Float32WithMeasure) : float32<1>
          and set (m:float32<1>) = this.matrix.M33 <- m |> float32
        member this.M34
          with get() = (this.matrix.M34 |> Float32WithMeasure) : float32<1>
          and set (m:float32<1>) = this.matrix.M34 <- m |> float32
        member this.M41
          with get() = (this.matrix.M41 |> Float32WithMeasure) : float32<'u>
          and set (m:float32<'u>) = this.matrix.M41 <- m |> float32
        member this.M42
          with get() = (this.matrix.M42 |> Float32WithMeasure) : float32<'u>
          and set (m:float32<'u>) = this.matrix.M42 <- m |> float32
        member this.M43
          with get() = (this.matrix.M43 |> Float32WithMeasure) : float32<'u>
          and set (m:float32<'u>) = this.matrix.M43 <- m |> float32
        member this.M44
          with get() = (this.matrix.M44 |> Float32WithMeasure) : float32<1>
          and set (m:float32<1>) = this.matrix.M44 <- m |> float32

        override this.ToString() = this.matrix.ToString()

        new(m11: float32<1>, m12: float32<1>, m13: float32<1>, m14: float32<1>,
            m21: float32<1>, m22: float32<1>, m23: float32<1>, m24: float32<1>,
            m31: float32<1>, m32: float32<1>, m33: float32<1>, m34: float32<1>,
            m41: float32<'u>, m42: float32<'u>, m43: float32<'u>, m44: float32<1>) =
                { matrix = Microsoft.Xna.Framework.Matrix(  m11 |> float32, m12 |> float32, m13 |> float32, m14 |> float32,
                                                            m21 |> float32, m22 |> float32, m23 |> float32, m24 |> float32,
                                                            m31 |> float32, m32 |> float32, m33 |> float32, m34 |> float32,
                                                            m41 |> float32, m42 |> float32, m43 |> float32, m44 |> float32)}
        new(m: float32<_>) =
            { matrix = Microsoft.Xna.Framework.Matrix(  m |> float32, m |> float32, m |> float32, m |> float32,
                                                        m |> float32, m |> float32, m |> float32, m |> float32,
                                                        m |> float32, m |> float32, m |> float32, m |> float32,
                                                        m |> float32, m |> float32, m |> float32, m |> float32)}

        private new(m: Microsoft.Xna.Framework.Matrix) = { matrix = m }

        static member (*) (m1:Matrix<'u>, m2:Matrix<'u2>) =
            Matrix<1>(Microsoft.Xna.Framework.Matrix.Multiply (m1.matrix, m2.matrix))

        static member Identity with get() = Matrix<'u>(Microsoft.Xna.Framework.Matrix.Identity)

        static member CreateFromAxisAngle (v:Vector3<1>,a:float32<rad>) =
            Matrix<1>(Microsoft.Xna.Framework.Matrix.CreateFromAxisAngle (v.vector, a |> float32))

        static member Transpose (m1:Matrix<'u>) =
            Matrix<1>(Microsoft.Xna.Framework.Matrix.Transpose (m1.matrix))

        static member CreateRotationX (a:float32<rad>) =
            Matrix<1>(Microsoft.Xna.Framework.Matrix.CreateRotationX (a |> float32))

        static member CreateRotationY (a:float32<rad>) =
            Matrix<1>(Microsoft.Xna.Framework.Matrix.CreateRotationY (a |> float32))

        static member CreateRotationZ (a:float32<rad>) =
            Matrix<1>(Microsoft.Xna.Framework.Matrix.CreateRotationZ (a |> float32))

        static member CreateTranslation (v:Vector3<_>) =
            Matrix<1>(Microsoft.Xna.Framework.Matrix.CreateTranslation (v.vector))

        static member CreateFromAxis (right:Vector3<1>, up:Vector3<1>, forward:Vector3<1>) =
            Matrix<_>(  right.X,    right.Y,    right.Z,    0.0f<1>,
                        up.X,       up.Y,       up.Z,       0.0f<1>,
                        -forward.X, -forward.Y, -forward.Z, 0.0f<1>,
                        0.0f<_>,    0.0f<_>,    0.0f<_>,    1.0f<1>)

        static member CreateFromAxisAndTranslation (right:Vector3<1>, up:Vector3<1>, forward:Vector3<1>, transl:Vector3<'u>) =
            Matrix<_>(  right.X,    right.Y,    right.Z,    0.0f<1>,
                        up.X,       up.Y,       up.Z,       0.0f<1>,
                        -forward.X, -forward.Y, -forward.Z, 0.0f<1>,
                        transl.X,   transl.Y,   transl.Z,   1.0f<1>)

        static member BuildViewMatrix (up:Vector3<_>, forward:Vector3<_>, position:Vector3<'u>) =
            let newForward = forward.Normalized()
            let newRight = Vector3<_>.Cross(newForward, up)
            let newUp = up.Normalized()
            let newForward = Vector3<_>.Cross(newUp, newRight)
            let newRight = newRight.Normalized()

            let x = -Vector3<_>.Dot(position, newRight)
            let y = -Vector3<_>.Dot(position, newUp)
            let z = Vector3<_>.Dot(position, newForward)

            Matrix<'u>( newRight.X,     newUp.X,    -newForward.X,  0.0f<1>,
                        newRight.Y,     newUp.Y,    -newForward.Y,  0.0f<1>,
                        newRight.Z,     newUp.Z,    -newForward.Z,  0.0f<1>,
                        x,              y,          z,              1.0f<1>)

        static member BuildViewMatrix (up:Vector3<1>, forward:Vector3<1>, position:Vector3<'u>, newRight:Vector3<1> ref) =
            let newForward = forward.Normalized()
            newRight := Vector3<_>.Cross(newForward, up)
            let newUp = up.Normalized()
            let newForward = Vector3<_>.Cross(newUp, !newRight)
            let newRight = (!newRight).Normalized()

            let x = -Vector3<_>.Dot(position, newRight)
            let y = -Vector3<_>.Dot(position, newUp)
            let z = Vector3<_>.Dot(position, newForward)

            Matrix<'u>( newRight.X,     newUp.X,    -newForward.X,  0.0f<1>,
                        newRight.Y,     newUp.Y,    -newForward.Y,  0.0f<1>,
                        newRight.Z,     newUp.Z,    -newForward.Z,  0.0f<1>,
                        x,              y,          z,              1.0f<1>)

        static member BuildViewMatrix (right:Vector3<1>, up:Vector3<1>, forward:Vector3<1>, position:Vector3<'u>) =
            let x = -Vector3<_>.Dot(position, right)
            let y = -Vector3<_>.Dot(position, up)
            let z = Vector3<_>.Dot(position, forward)

            Matrix<'u>( right.X,    up.X,   -forward.X,     0.0f<1>,
                        right.Y,    up.Y,   -forward.Y,     0.0f<1>,
                        right.Z,    up.Z,   -forward.Z,     0.0f<1>,
                        x,          y,      z,              1.0f<1>)

        member this.GetNative() = this.matrix
    end



// Vector3 type extension... now Matrix type definition is visible...
type Vector3<[< Measure >] 'u> with
    static member Transform (v:Vector3<'u>,m:Matrix<_>) =
        Vector3<'u>(Microsoft.Xna.Framework.Vector3.Transform (v.vector, m.matrix))